iT邦幫忙

2021 iThome 鐵人賽

DAY 2
0

JUMP!
沒有其他選擇,執行到這就一定得跳!
這次有兩種不同格式的指令,分別是 J-type 的 JAL,
以及 I-type 的 JALR。

另外要注意的是,
如果跳到不合法的位置會觸發 instruction-address-misaligned exception。

J-type

指令格式如下:

|31                      12|11   7|6       0|
+-------------------------------------------+
|           imm            |  rd  | opcode  |
+-------------------------------------------+

I-type

指令格式如下:

|31     20|19   15|14    12|11   7|6       0|
+-------------------------------------------+
|   imm   |  rs1  | funct3 |  rd  | opcode  |
+-------------------------------------------+

JAL

是一種依照目前指令所在的 Address + Offset 決定跳到哪的指令,
因為 RISC-V 支援 Compress Extension,
必須支援跳到的位置是 Half Word Alignment,
所以這道指令的 imm 是以 Half Word 當作單位,
要乘 2 才會是真正的 Offset。

另外要注意的是,只有在支援 Compress Extension 的時候,
跳到的位置限制才會放寬到 Half Word Alignment,
不支援的情況下要特別注意 Alignment 的問題。

rd = current_pc + 4
pc = current_pc + (imm * 2)

|31                      12|11   7|6       0|
+-------------------------------------------+
|           imm            |  rd  | 1101111 |
+-------------------------------------------+

JALR

這邊跟上面不太一樣,是完全依照 register 的內容當成 base,
再加上 offset 決定最後跳到的位置,
特別注意的是 register 內的直就直接當作 address 用,
不用為了Alignment 另外乘 2,
也可以跟前面實作的 LUI 配合使用,
20 + 12 bit 的 imm 值可以跳到 Address Space 的任意位置。

當 rs1 設定為 x0 的時候,
只要單行指令跳到 address space 最高/最低的 2KiB 的任意位置,
可以支援簡單的 Run Time Library。

另外,雖然規格書明訂最後運算的結果會捨去最後一個 bit,
使用上還是和 JAL 一樣要注意 Alignment 的問題!

rd = current_pc + 4
pc = (rs1 + imm) & (~0x1)

|31     20|19   15|14    12|11   7|6       0|
+-------------------------------------------+
|   imm   |  rs1  |  000   |  rd  | 1100111 |
+-------------------------------------------+

JR

跟前面遇過的指令一樣,
這道指令也是 opcode 和 func3 都跟 JALR 一樣,
只是我們不需要回來的位置了,
所以把 rd 設定為 x0。

x0 = current_pc + 4
pc = (rs1 + imm) & (~0x1)

|31     20|19   15|14    12|11   7|6       0|
+-------------------------------------------+
|   imm   |  rs1  |  000   |  0   | 1100111 |
+-------------------------------------------+

實際程式

github 頁面 Tag: ITDay18

糟糕,JAL 的 imm 格式讓實作變得有點髒兮兮的了,
幸好偉大的 sc_dt 提供方便的功能,
讓猴子寫的 code 可以被未來的猴子看懂拉!

//before
	auto offset = ((imm & ~0x7FFFF) |         //imm[30:19] > offset[31:20]
	               (imm & 0xFF) << 11 |       //imm[7:0] > offset[19:12]
	               (imm & (0x1 << 8)) << 2 |  //imm[8] > offset[11]
	               (imm & (0x3FF << 9)) >> 9) //imm[18:9] > offset[10:1]
	              << 1; //need to refactor to readable monkey style
//after
int32_t INSTRUCTION_DECODER::get_imm_j()
{
	auto value = sc_dt::sc_int<32>();
	value(20, 20) = instruction_value(31, 31);
	value(19, 12) = instruction_value(19, 12);
	value(11, 11) = instruction_value(20, 20);
	value(10, 1) = instruction_value(31, 21);
	value <<= 12;
	value >>= 12;
	return value;
}

把取得 offset 的功能搬到 Decoder 改寫後,
指令實作的部分就變得簡單很多。

//executor.cpp
...
		case INSTRUCTION_DECODER_INTERFACE::JAL_OP:
			JAL_E();
			break;
		case INSTRUCTION_DECODER_INTERFACE::JALR_OP:
			switch (instruction_decoder->get_func3()) {
				case INSTRUCTION_DECODER_INTERFACE::JALR_FN3:
					JALR_E();
					break;
				default:
					std::cout << "INVALID: Func3 in JALR_OP :" << instruction_decoder->get_func3() << std::endl;
					break;
			}
...
void EXECUTOR::JAL_E()
{
	auto offset = instruction_decoder->get_imm_j();
	auto rd = instruction_decoder->get_rd();

	register_file->set_value_integer(rd, new_pc);
	new_pc = register_file->get_pc() + offset;
}

void EXECUTOR::JALR_E()
{
	auto offset = instruction_decoder->get_imm(31, 20);
	auto rs1 = instruction_decoder->get_rs1();
	auto rd = instruction_decoder->get_rd();

	register_file->set_value_integer(rd, new_pc);
	new_pc = (register_file->get_pc() + offset) & ~0x1;
}
//instructionDecoderInterface.h
...
		JAL_OP = 0b1101111,
		JALR_OP = 0b1100111,
...
		JALR_FN3 = 0b000,
...

偷偷跟你們說個秘密:
前天有隻猴子犯了小小的錯誤,
我偷偷笑了很久,很缺德,現在在反省,
這件事不要跟其他人說喔!

執行結果

前面的部分省略,
因為把 imm 設定為 -2,乘 2 之後就是前一道指令,
可以看到 JAL 執行之後又跳回 SH 再執行一次。

$ make run
...
LHU
rs1: 0
rd: 8
addr: 4
value: 33043
SH
rs1: 0
rs2: 7
addr: 1024
JAL
rd: 0
new_pc: 48
SH
rs1: 0
rs2: 7
addr: 1024
JAL
rd: 0
new_pc: 48

上一篇
Computer Architecture: Memory Hierarchy
下一篇
RISC-V: Branch 指令
系列文
猴子都寫得出來的 RISC-V CPU Emulator31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言